package com.cskaoyan.mall.payment.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cskaoyan.mall.common.constant.ResultCodeEnum;
import com.cskaoyan.mall.common.result.Result;
import com.cskaoyan.mall.order.dto.OrderInfoDTO;
import com.cskaoyan.mall.pay.api.dto.PaymentInfoDTO;
import com.cskaoyan.mall.payment.client.OrderApiClient;
import com.cskaoyan.mall.payment.constant.PaymentStatus;
import com.cskaoyan.mall.payment.constant.PaymentType;
import com.cskaoyan.mall.payment.converter.PaymentInfoConverter;
import com.cskaoyan.mall.payment.mapper.PaymentInfoMapper;
import com.cskaoyan.mall.payment.model.PaymentInfo;
import com.cskaoyan.mall.payment.pay.PayHelpFactory;
import com.cskaoyan.mall.payment.pay.PayHelper;
import com.cskaoyan.mall.payment.pay.alipay.AlipayHelper;
import com.cskaoyan.mall.payment.service.PayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;

/**
 * @Author Pudding
 * @Date 2024/7/19 17:32
 */
@Service
public class PayServiceImpl implements PayService {

    @Autowired
    OrderApiClient orderApiClient;
    @Autowired
    PaymentInfoConverter paymentInfoConverter;
    @Autowired
    PayHelpFactory payHelpFactory;
    @Autowired
    PaymentInfoMapper paymentInfoMapper;

    /**
     * 1. 支付宝支付，获取支付页面表单
     * @param orderId
     * @return
     */
    @Override
    public String createPay(Long orderId, String payTypeName) {

        //1. 通过订单id查询订单信息
        OrderInfoDTO orderInfoDTO = orderApiClient.getOrderInfoDTO(orderId);

        //2. 校验支付对应的订单状态是否为未支付
            //如果是已支付或已关闭，则直接return "该订单支付状态异常！"
        String orderStatus = orderInfoDTO.getOrderStatus();
        if (!orderStatus.equals(PaymentStatus.UNPAID.name())){
            return "该订单支付状态异常！";
        }

        //3. 保存一条支付记录到数据库的支付表
        this.savePaymentInfo(orderInfoDTO, PaymentType.ALIPAY.name());

        //4. 调用支付宝SDK，生成支付表单页面（支付表单实际上就是一个支付页面，是一个html的字符串）
        PayHelper payHelper = payHelpFactory.getPayHelper(payTypeName);
        String paymentPage = payHelper.getPaymentPage(orderInfoDTO);

        //5. 返回支付表单
        return paymentPage;
    }


    /**
     * 2. 保存一条支付记录到数据库的支付表
     * @param orderInfoDTO
     * @param paymentTypeName
     */
    @Override
    public void savePaymentInfo(OrderInfoDTO orderInfoDTO, String paymentTypeName) {

        //1. 把orderInfoDTO转换为PO对象paymentInfo
        PaymentInfo paymentInfo = paymentInfoConverter.contvertOrderInfoDTO2PaymentInfo(orderInfoDTO);
        //1.1 设置支付类型：支付宝
        paymentInfo.setPaymentType(paymentTypeName);
        //1.2 设置支付状态，为未支付
        paymentInfo.setPaymentStatus(PaymentStatus.UNPAID.name());

        //2. 先判断一下，该订单记录在支付宝中是否有对应的支付记录
        //如果有，那就不新增了，如果没有再新增
        PaymentInfoDTO paymentInfoDTO = this.queryPaymentInfoByOutTradeNoAndPaymentType(orderInfoDTO.getOutTradeNo(), paymentTypeName);
        if (paymentInfoDTO == null){
            //3. 将paymentInfo保存到数据库
            paymentInfo.setId(null);
            paymentInfoMapper.insert(paymentInfo);
        }

        // 当然，目前在这个支付记录中，有一些字段目前是没有的
        // trade_no、callback_time、callback_content
        // 以上的字段，需要等到异步通知回调回来了之后，再去设值
    }

    /**
     * 3. 通过外部交易流水号和交易渠道查询支付记录
     */
    @Override
    public PaymentInfoDTO queryPaymentInfoByOutTradeNoAndPaymentType(String outTradeNo, String payTypeName) {

        //3.1 构建查询条件
        LambdaQueryWrapper<PaymentInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PaymentInfo::getOutTradeNo, outTradeNo)
                .eq(PaymentInfo::getPaymentType, payTypeName);

        //3.2 查询
        PaymentInfo paymentInfo = paymentInfoMapper.selectOne(lambdaQueryWrapper);

        //3.3 将PO对象paymentInfo转换为DTO对象PaymentInfoDTO
        PaymentInfoDTO paymentInfoDTO = paymentInfoConverter.convertPaymentInfoToDTO(paymentInfo);

        return paymentInfoDTO;
    }


    /**
     * 修改支付记录表
     * 1. 修改支付表的状态
     * 2. 在支付服务中：远程调用订单服务，修改订单表的状态[已支付]
     * 3. 在订单服务中：远程调用仓储服务：扣减库存
     *      如果这笔订单中的商品不在同一个仓库中，那么仓储服务在扣减库存的时候，会调用订单服务的接口，进行拆单;
     *      如果在同一个仓库中，跳过此步
     * @param outTradeNo        交易编号
     * @param paymentTypeName   支付类型的名字
     * @param paramsMap
     * @return
     */
    @Override
    public Boolean successPay(String outTradeNo, String paymentTypeName, Map<String, String> paramsMap) {

        try {
            //1. 修改支付表的状态
            //1.1 根据outTradeNo和paymentTypeName来查询支付信息表中记录
            PaymentInfoDTO paymentInfoDTO = this.queryPaymentInfoByOutTradeNoAndPaymentType(outTradeNo, paymentTypeName);
            //1.2 新建一个对象来存放需要修改字段的信息
            PaymentInfo paymentInfo = new PaymentInfo();
            paymentInfo.setId(paymentInfoDTO.getId());
            paymentInfo.setPaymentStatus(PaymentStatus.PAID.name());        //修改支付表的状态
            paymentInfo.setTradeNo(paramsMap.get("trade_no"));              //设置支付宝交易流水号
            paymentInfo.setCallbackTime(new Date());                        //设置回调时间
            paymentInfo.setCallbackContent(JSON.toJSONString(paramsMap));   //设置回调内容
            //1.3 根据id修改支付记录表的信息
            int affect = paymentInfoMapper.updateById(paymentInfo);
            if (affect < 1){
                throw new RuntimeException("修改支付表的状态失败！");
            }

            //2．远程调用订单服务，修改订单表的状态[已支付]
            Result result = orderApiClient.successPay(paymentInfoDTO.getOrderId());
            if (!result.getCode().equals(ResultCodeEnum.SUCCESS.getCode())){
                throw new RuntimeException("远程调用修改订单表的状态失败！");
            }

            return true;

        } catch (RuntimeException e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 5. 修改支付状态
     * @param outTradeNo       交易编号
     * @param paymentTypeName  支付类型的名字
     * @param paymentStatus    支付状态
     */
    @Override
    public void updatePaymentStatus(String outTradeNo, String paymentTypeName, PaymentStatus paymentStatus) {

        //5.1 构建修改条件
        LambdaUpdateWrapper<PaymentInfo> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(PaymentInfo::getOutTradeNo, outTradeNo)
                .eq(PaymentInfo::getPaymentType, paymentTypeName)
                .set(PaymentInfo::getPaymentStatus, paymentStatus.name());

        //5.2 进行修改
        paymentInfoMapper.update(null, lambdaUpdateWrapper);

    }
}
